#!/usr/bin/env python
# -*- encoding: utf-8 -*-
"""
主题: 减少可调用对象的参数个数
问题: 你有一个被其他python代码使用的callable对象，可能是一个回调函数或者是一个处理器， 但是它的参数太多了，导致调用时出错。
提示 : 
"""

from functools import partial
import math
import logging
from multiprocessing import Pool
from socketserver import StreamRequestHandler, TCPServer


def recipe1():
    s1 = partial(spam, 1)
    s1(2, 3, 4)
    s1(4, 5, 6)

    s1 = partial(spam, d=42)
    s1(2, 3, 4)
    s1(4, 5, 6)


def recipe2():
    '''以某个点为基点，根据点和基点之间的距离来排序所有的这些点'''
    points = [(1, 2), (3, 4), (5, 6), (7, 8)]
    pt = (4, 3)     # 基点
    points.sort(key=partial(distance, pt))
    # lambda表达式也能实现
    points.sort(key=lambda p: distance(pt, p))
    print(f"{points = }")


def recipe3():
    '''微调其他库函数所使用的回调函数的参数'''
    logging.basicConfig(level=logging.DEBUG)
    log = logging.getLogger('test')

    p = Pool()
    p.apply_async(add, (3, 4), callback=partial(output_result, log=log))
    # lambda表达式也能实现
    p.apply_async(
        add, (3, 4), callback=lambda result: output_result(result, log))
    p.close()
    p.join()


def recipe4():
    serv = TCPServer(('', 15000), partial(EchoHandler, ack=b'RECEIVED:'))
    print(f"{serv = }")

    # lambda表达式也能实现
    serv = TCPServer(('', 15001),
                     lambda *args, **kwargs: EchoHandler(*args, ack=b'RECEIVED:', **kwargs))
    print(f"{serv = }")

    # serv.serve_forever()


class EchoHandler(StreamRequestHandler):
    '''简单的echo服务器'''
    # ack is added keyword-only argument. *args, **kwargs are
    # any normal parameters supplied (which are passed on)

    def __init__(self, *args, ack, **kwargs):
        self.ack = ack
        super().__init__(*args, **kwargs)

    def handle(self):
        for line in self.rfile:
            self.wfile.writable(self.ack + line)


def output_result(result, log=None):
    if log is not None:
        log.debug('Got: %r', result)


def add(x, y):
    return x + y


def distance(p1, p2):
    '''(x,y)坐标元组。 你可以使用下面的函数来计算两点之间的距离'''
    x1, y1 = p1
    x2, y2 = p2
    return math.hypot(x2 - x1, y2 - y1)


def spam(a, b, c, d):
    print(a, b, c, d)


def main():
    print('recipe1'.center(20, '*'))
    recipe1()
    print('recipe2'.center(20, '*'))
    recipe2()
    print('recipe3'.center(20, '*'))
    recipe3()
    print('recipe4'.center(20, '*'))
    recipe4()


if __name__ == '__main__':
    main()
